/*
 * linux 定时器另一种方法：timerfd
 * 可以从文件描述符中读取其所创建定时器的到期通知
 * ********************************************
 * @ int timerfd_create(int clockid, int flags)
 *   clockid:CLOCK_REALTIME  CLOCK_MONOTONIC
 *   flags: TFD_CLOEXEC  TFD_NONBLOCK
 * *********************************************
 * @ int timerfd_settime(int fd, int flags, const struct itimerspec *new_value,
 *                      struct itimerspec *old_value);
 *   new_value:定时器指定的新设置
 *   old_value:返回定时器的前一个设置
 * *************************************************************
 * @ int timerfd_gettime(int fd, struct itimerspec *curr_value)
 *   通timer_gettime()一样
 * **************************************************************
 * @ 关闭timerfd定时器
 *   close(fd)
 * *************************************************************
 * @ 读 timerfd
 *    ssize_t read(timer_fd, &buff, sizeof(uint64_t))
 *      buff中包含已发生的到期次数
 */
#include <time.h>
#include <stdint.h>
#include <sys/timerfd.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>

int main()
{
    struct itimerspec ts;
    struct timespec start, now;
    int maxExp = 100, fd, secs, nanosecs;
    uint64_t numExp, totalExp;
    ssize_t s;

    ts.it_interval.tv_sec = 1;
    ts.it_value.tv_sec = 1;

    fd = timerfd_create(CLOCK_REALTIME, 0);
    if (fd < 0)
    {
        perror("create timerfd\n");
        goto err_create;
    }

    if (-1 == timerfd_settime(fd, 0, &ts, NULL))
    {
        perror("timerfd set\n");
        goto err_set;
    }

    if (clock_gettime(CLOCK_MONOTONIC, &start) == -1)
    {
        perror("get time\n");
        goto err_gettime;
    }

    for (totalExp = 0; totalExp < maxExp;)
    {
        s = read(fd, &numExp, sizeof(uint64_t));
        if (s != sizeof(uint64_t))
        {
            perror("err read\n");
            goto err_read;
        }

        totalExp += numExp;

        if (clock_gettime(CLOCK_MONOTONIC, &now) == -1)
        {
            perror("get time\n");
            goto err_gettime;
        }

        secs = now.tv_sec - start.tv_sec;
        nanosecs = now.tv_nsec - start.tv_nsec;

        if (nanosecs < 0)
        {
            secs--;
            nanosecs += 1000000000;
        }

        printf("%d.%03d:experions read:%1lu, totaol=%1lu\n", secs, (nanosecs + 500000) / 1000000,
               (unsigned long long)numExp, (unsigned long long)totalExp);
    }
err_read:
err_gettime:
err_set:
    close(fd);
err_create:
    exit(1);
}